#include "image_process.hpp"
/*
功能：对菜单上的参数进行初始化设置
输入参数：菜单结构体指针
返回值：无
*/
void menu_init(MENU * menu)
{
    menu->text        =     false;                    //菜单默认关
    menu->target      =     1;                        //目标选择
    menu->AWB         =     0;                        //白平衡校准
    menu->brightness  =     brightness_def;           //亮度默认值
    menu->contrast    =     contrast_def;             //对比度默认值
    menu->r_hue       =     r_hue_def;                //红色色调默认值
    menu->g_hue       =     g_hue_def;                //绿色色调默认值
    menu->b_hue       =     b_hue_def;                //蓝色色调默认值
    menu->multiple    =     false;                    //放大倍数默认值
    menu->sharpness   =     sharpness_def;            //锐度默认值
    menu->blur        =     blur_def;                 //模糊度默认值
    menu->mask        =     false;                    //边缘遮罩默认关
    menu->record      =     false;                    //录屏默认关
    menu->mount       =     0;                        //是否能挂载成功
}
/*
功能：将菜单的参数复制到副本，防止同一帧内参数发生更改
输入参数1：菜单结构体
输入参数2：菜单结构体副本的指针
返回值：无
*/
void menu_copy(MENU menu,MENU *menu_cp)
{
    /*menu_cp->text        =  menu.text;        
    menu_cp->target      =  menu.target;        
    menu_cp->AWB         =  menu.AWB;           
    menu_cp->brightness  =  menu.brightness;    
    menu_cp->contrast    =  menu.contrast ;     
    menu_cp->r_hue       =  menu.r_hue ;       
    menu_cp->g_hue       =  menu.g_hue;         
    menu_cp->b_hue       =  menu.b_hue;         
    menu_cp->multiple    =  menu.multiple;      
    menu_cp->sharpness   =  menu.sharpness;     
    menu_cp->blur        =  menu.blur;           
    menu_cp->mask        =  menu.mask;          
    menu_cp->record      =  menu.record;  */
    memcpy(menu_cp,&menu,sizeof(menu));      
}
/*
功能：将图像裁剪为720*720，降低处理的开销
输入参数：源图像
返回值：无
*/
void image_cut(Mat & frame)
{
    Mat tmp;
    /*Rect roi(212,212,1080,1080);
    frame(roi).copyTo(tmp);*/
    resize(frame,tmp,Size(720,720),0,0,INTER_LANCZOS4);
    frame = tmp;
}
/*
功能：进行白平衡校准，获取增益参数
参数1：输入图像
返回值：RGB三通道的增益参数
*/
cv::Scalar image_gain_awb(const cv::Mat& src_rgb) 
{
    if (src_rgb.empty() || src_rgb.channels() != 3) 
        return cv::Scalar(1.0, 1.0, 1.0); // 默认中性增益

    float ratio = 0.1;

    //确保输入为浮点型 (CV_32FC3) 
    cv::Mat src_float;
    src_rgb.convertTo(src_float, CV_32F);

    // 计算每个像素的RGB总和 
    cv::Mat sum;
    cv::transform(
        src_float, 
        sum, 
        cv::Matx13f(1, 1, 1) // 使用 1x3 变换矩阵
    );

    // 确定前ratio%亮度的阈值
    cv::Mat sorted;
    cv::sort(sum.reshape(1), sorted, cv::SORT_DESCENDING);
    int idx = static_cast<int>(sorted.rows * ratio);
    float T = sorted.at<float>(idx);

    // 创建亮区掩膜 (sum为单通道)
    cv::Mat mask = (sum >= T);

    // 计算亮区RGB均值 (注意通道顺序: R=通道0, G=通道1, B=通道2)
    cv::Scalar meanRGB = cv::mean(src_float, mask);

    // 计算增益 (防止除零)
    double maxVal;
    cv::minMaxLoc(sum, nullptr, &maxVal, nullptr, nullptr, mask);
    double gainR = (meanRGB[0] > 1e-5) ? maxVal / meanRGB[0] : 1.0;
    double gainG = (meanRGB[1] > 1e-5) ? maxVal / meanRGB[1] : 1.0;
    double gainB = (meanRGB[2] > 1e-5) ? maxVal / meanRGB[2] : 1.0;

    // 增益范围限制在 [0.5, 3.0] 之间
    /*gainR = std::clamp(gainR, 0.5, 3.0);
    gainG = std::clamp(gainG, 0.5, 3.0);
    gainB = std::clamp(gainB, 0.5, 3.0);*/

    return cv::Scalar(gainR, gainG, gainB);
}
/*
功能：调整图像亮度和对比度
参数1：源图像
参数2：菜单结构体
返回值：无
*/
void image_brightness_contrast(Mat & frame,MENU menu)
{
    Mat tmp;
    int beta = menu.brightness - brightness_def;  // brightness_def=100
    beta = std::clamp(beta, -100, 100);  // 限制β在[-100,100]范围内
    frame.convertTo(tmp,-1,menu.contrast,beta);
    frame = tmp.clone();
}
/*
功能：调整红绿蓝三色色调
参数1：源图像
参数2：菜单结构体
返回值：无
*/
void image_adjustRGBHues(Mat & frame, MENU menu) 
{
    //+-25
    int red_shift = (100 - menu.r_hue - 50) / 2.0;
    //+-25
    int green_shift = (menu.g_hue - 50) / 2.0;
    //+-35
    int blue_shift = (menu.b_hue - 50) / 1.43;

    Mat adjusted_hsv;
    cvtColor(frame, adjusted_hsv, COLOR_RGB2HSV);
    
    // 分离HSV通道
    vector<Mat> hsv_channels;
    split(adjusted_hsv, hsv_channels);
    
    // 获取H通道
    Mat hue = hsv_channels[0].clone();
    
    // 创建颜色掩膜
    Mat red_mask_low, red_mask_high, red_mask;
    inRange(hue, 0, 10, red_mask_low);        // 红色低范围 (0-10)
    inRange(hue, 170, 180, red_mask_high);     // 红色高范围 (170-180)
    bitwise_or(red_mask_low, red_mask_high, red_mask); // 合并红色掩膜
    
    Mat green_mask;
    inRange(hue, 35, 85, green_mask);          // 绿色掩膜 (35-85)
    
    Mat blue_mask;
    inRange(hue, 100, 140, blue_mask);         // 蓝色掩膜 (100-140)
    
    // 应用色调偏移 - 使用指针操作提高效率
    for (int y = 0; y < hue.rows; y++) {
        for (int x = 0; x < hue.cols; x++) {
            uchar pixel = hue.at<uchar>(y, x);
            
            // 红色区域调整
            if (red_mask.at<uchar>(y, x) == 255) {
                int new_val = pixel + red_shift;
                if (new_val < 0) new_val += 180;
                else if (new_val >= 180) new_val -= 180;
                hue.at<uchar>(y, x) = static_cast<uchar>(new_val);
            }
            // 绿色区域调整
            else if (green_mask.at<uchar>(y, x) == 255) {
                int new_val = pixel + green_shift;
                if (new_val < 0) new_val += 180;
                else if (new_val >= 180) new_val -= 180;
                hue.at<uchar>(y, x) = static_cast<uchar>(new_val);
            }
            // 蓝色区域调整
            else if (blue_mask.at<uchar>(y, x) == 255) {
                int new_val = pixel + blue_shift;
                if (new_val < 0) new_val += 180;
                else if (new_val >= 180) new_val -= 180;
                hue.at<uchar>(y, x) = static_cast<uchar>(new_val);
            }
        }
    }
    
    // 合并调整后的通道
    hsv_channels[0] = hue;
    merge(hsv_channels, adjusted_hsv);
    
    // 转换回RGB
    cvtColor(adjusted_hsv, frame, COLOR_HSV2RGB);
}
/*
功能：对图像进行2倍放大
参数1：源图像
参数2：目标图像
返回值：无
*/
void image_zoom(Mat & frame)
{
    Mat dst;
    uint32_t src_width = frame.cols;
    uint32_t src_height = frame.rows;
    Rect roi(src_width / 8,src_height / 8, 540 , 540);
    resize(frame(roi),dst,Size(1080,1080),0,0,INTER_LANCZOS4);
    //frame = dst.clone();
    dst.copyTo(frame);
}
/*
功能：图像锐化调整
参数1：源图像
参数2：菜单结构体
返回值：无
*/
void image_USM(Mat & frame,MENU menu) 
{
    // 锐化强度 0.1 - 1.2
    double w = menu.sharpness / 91.0 + 0.1;  

    Mat yuv, channels[3], blurred;
    cvtColor(frame, yuv, COLOR_RGB2YUV);
    split(yuv, channels);
    // 仅对Y通道锐化
    GaussianBlur(channels[0], blurred, Size(11,11), 1.7);
    addWeighted(channels[0], 1+w, blurred, -w, 0, channels[0]);
    merge(channels, 3, yuv);
    cvtColor(yuv, frame, COLOR_YUV2RGB);
}
/*
功能：图像模糊
参数1：源图像
参数2：菜单结构体
返回值：无
*/
void image_blur(Mat & frame,MENU menu)
{
    Mat blurred;
    int ksize = round(menu.blur / 5.0) + 1;//任意正奇数,菜单范围0 - 100，计算范围1 - 21
    blur(frame, blurred, Size(ksize,ksize)); // 核尺寸 (ksize,ksize)
    frame = blurred.clone();
}
/*
功能：将图像裁减为圆形，其余部分为黑色并扩大为目标分辨率，扩大的部分用黑色填充
参数1：输入图像指针,直接对原图进行操作
参数2：目标横向分辨率
参数3：目标纵向分辨率
返回值：无
*/
void image_circle(Mat & frame)
{
    uint32_t src_width = frame.cols;
    uint32_t src_height = frame.rows;

    //创建黑色底色
    Mat mask(src_width,src_height,CV_8UC1,Scalar(0));
    //绘制实心白色圆形，保留区
    circle(mask,Point(src_width / 2,src_height / 2),src_width / 2,Scalar(255),FILLED);

    Mat tmp;
    //进行位运算，异或，即黑色圆形处保留，其余留黑
    bitwise_and(frame,frame,tmp,mask);

    frame = tmp.clone();
}
/*
功能：根据显示器分辨率将图像适配为合适的大小
输入参数1：源图像
输入参数2：显示器宽
输入参数3：显示器高
返回值：无
*/
void image_fit(Mat & frame,MENU menu,uint32_t dst_width,uint32_t dst_height)
{
    uint32_t src_width = frame.cols;
    uint32_t src_height = frame.rows;

    //创建显示区域
    Rect roi((dst_width - src_width) / 2,(dst_height - src_height) / 2,frame.cols,frame.rows);

    //初始化纯黑底色的图像
    Mat dst(dst_height,dst_width,CV_8UC3,Scalar(0,0,0));

    //与摄像头画面合并
    frame.copyTo(dst(roi));

    //重新拷贝到原图像
    dst.copyTo(frame);
    //frame = dst.clone();
}
/*
功能：将菜单文字显示到图像上
输入参数1：源图像
输入参数2：指向菜单结构体的指针
输入参数3；字体文件
返回值：无
*/
void image_menu_update(Mat frame,MENU * menu,Ptr <freetype::FreeType2> ft2)
{
    if(menu->text == false)
        return;

    char tmp_text[50];

    if(menu->AWB == 0)
        sprintf(tmp_text,"白平衡校准：");
    else if(menu->AWB == 1)
        sprintf(tmp_text,"白平衡校准：");
    else if(menu->AWB == 2)
        sprintf(tmp_text,"白平衡校准：已校准");
    ft2->putText(frame, tmp_text, Point(0, 50),30, WHITE_TEXT,FILLED, LINE_AA, true);

    sprintf(tmp_text,"亮度：");
    if(menu->target == 1)
        ft2->putText(frame, tmp_text, Point(0, 100),30, ORA_TEXT,FILLED, LINE_AA, true);
    else
        ft2->putText(frame, tmp_text, Point(0, 100),30, WHITE_TEXT,FILLED, LINE_AA, true);
    rectangle(frame,Point(120,75),Point(120 + menu->brightness,105),Scalar(255,255,255),-1);
    sprintf(tmp_text,"%d",menu->brightness);
    ft2->putText(frame, tmp_text, Point(320, 100),30, WHITE_TEXT,FILLED, LINE_AA, true);

    sprintf(tmp_text,"对比度：");
    if(menu->target == 2)
        ft2->putText(frame, tmp_text, Point(0, 150),30, ORA_TEXT,FILLED, LINE_AA, true);
    else
        ft2->putText(frame, tmp_text, Point(0, 150),30, WHITE_TEXT,FILLED, LINE_AA, true);
    rectangle(frame,Point(120,125),Point(120 + menu->contrast / 2.0 * 200,155),Scalar(255,255,255),-1);
    sprintf(tmp_text,"%.2lf",menu->contrast);    
    ft2->putText(frame, tmp_text, Point(320, 150),30, WHITE_TEXT,FILLED, LINE_AA, true);

    sprintf(tmp_text,"红色调：");
    if(menu->target == 3)
        ft2->putText(frame, tmp_text, Point(0, 200),30, ORA_TEXT,FILLED, LINE_AA, true);
    else
        ft2->putText(frame, tmp_text, Point(0, 200),30, WHITE_TEXT,FILLED, LINE_AA, true);
    rectangle(frame,Point(120,175),Point(120 + menu->r_hue * 2.0,205),Scalar(255,255,255),-1);
    sprintf(tmp_text,"%d",menu->r_hue);
    ft2->putText(frame, tmp_text, Point(320, 200),30, WHITE_TEXT,FILLED, LINE_AA, true);

    sprintf(tmp_text,"绿色调：");
    if(menu->target == 4)
        ft2->putText(frame, tmp_text, Point(0, 250),30, ORA_TEXT,FILLED, LINE_AA, true);
    else
        ft2->putText(frame, tmp_text, Point(0, 250),30, WHITE_TEXT,FILLED, LINE_AA, true);
    rectangle(frame,Point(120,225),Point(120 + menu->g_hue * 2.0,255),Scalar(255,255,255),-1);
    sprintf(tmp_text,"%d",menu->g_hue);
    ft2->putText(frame, tmp_text, Point(320, 250),30, WHITE_TEXT,FILLED, LINE_AA, true);

    sprintf(tmp_text,"蓝色调：");
    if(menu->target == 5)
        ft2->putText(frame, tmp_text, Point(0, 300),30, ORA_TEXT,FILLED, LINE_AA, true);
    else
        ft2->putText(frame, tmp_text, Point(0, 300),30, WHITE_TEXT,FILLED, LINE_AA, true);
    rectangle(frame,Point(120,275),Point(120 + menu->b_hue * 2.0,305),Scalar(255,255,255),-1);
    sprintf(tmp_text,"%d",menu->b_hue);
    ft2->putText(frame, tmp_text, Point(320, 300),30, WHITE_TEXT,FILLED, LINE_AA, true);

    menu->multiple ? sprintf(tmp_text,"倍数：2") : sprintf(tmp_text,"倍数：1");
    if(menu->target == 6)
        ft2->putText(frame, tmp_text, Point(0, 350),30, ORA_TEXT,FILLED, LINE_AA, true);
    else
        ft2->putText(frame, tmp_text, Point(0, 350),30, WHITE_TEXT,FILLED, LINE_AA, true);

    sprintf(tmp_text,"锐度：");
    if(menu->target == 7)
        ft2->putText(frame, tmp_text, Point(0, 400),30, ORA_TEXT,FILLED, LINE_AA, true);
    else
        ft2->putText(frame, tmp_text, Point(0, 400),30, WHITE_TEXT,FILLED, LINE_AA, true);
    rectangle(frame,Point(120,375),Point(120 + menu->sharpness * 2.0,405),Scalar(255,255,255),-1);
    sprintf(tmp_text,"%d",menu->sharpness);
    ft2->putText(frame, tmp_text, Point(320, 400),30, WHITE_TEXT,FILLED, LINE_AA, true);

    sprintf(tmp_text,"模糊度：");
    if(menu->target == 8)
        ft2->putText(frame, tmp_text, Point(0, 450),30, ORA_TEXT,FILLED, LINE_AA, true);
    else
        ft2->putText(frame, tmp_text, Point(0, 450),30, WHITE_TEXT,FILLED, LINE_AA, true);
    rectangle(frame,Point(120,425),Point(120 + menu->blur * 2.0,455),Scalar(255,255,255),-1);
    sprintf(tmp_text,"%d",menu->blur);
    ft2->putText(frame, tmp_text, Point(320, 450),30, WHITE_TEXT,FILLED, LINE_AA, true);

    menu->mask ? sprintf(tmp_text,"边缘遮罩：开") : sprintf(tmp_text,"边缘遮罩：关");
    if(menu->target == 9)
        ft2->putText(frame, tmp_text, Point(0, 500),30, ORA_TEXT,FILLED, LINE_AA, true);
    else
        ft2->putText(frame, tmp_text, Point(0, 500),30, WHITE_TEXT,FILLED, LINE_AA, true);

    menu->record ? sprintf(tmp_text,"录屏：开") : sprintf(tmp_text,"录屏：关");
    ft2->putText(frame, tmp_text, Point(0, 550),30, WHITE_TEXT,FILLED, LINE_AA, true);

    if(menu->mount == 1)
    {
        sprintf(tmp_text,"优盘挂载错误");
        ft2->putText(frame, tmp_text, Point(0, 600),30, WHITE_TEXT,FILLED, LINE_AA, true);
    }
    else if(menu->mount == 2)
    {
        sprintf(tmp_text,"优盘挂载成功，开始录屏");
        ft2->putText(frame, tmp_text, Point(0, 600),30, WHITE_TEXT,FILLED, LINE_AA, true);
    }
    else if(menu->mount == 3)
    {
        sprintf(tmp_text,"录屏结束，优盘弹出成功");
        ft2->putText(frame, tmp_text, Point(0, 600),30, WHITE_TEXT,FILLED, LINE_AA, true);
    }
}
/*
功能：将图像数据格式转换为XRGB888并写入drm的缓冲区
输入参数1：源图像
输入参数2：drm的缓冲区
返回值：无
*/
void image_RGB_to_XRGB(Mat frame,uint32_t * drm_show_buf)
{
    Mat tmp(frame.rows, frame.cols, CV_8UC4, drm_show_buf);
    
    // 确保输入内存连续
    if (!frame.isContinuous()) {
        frame = frame.clone();
    }

    // 创建包含4个通道的矩阵数组
    std::vector<Mat> channels;
    channels.reserve(4);
    
    // 分离RGB通道（注意OpenCV默认BGR顺序）
    std::vector<Mat> rgbChannels(3);
    split(frame, rgbChannels);
    
    // 通道顺序调整为：Alpha, R, G, B
    // 注意：原始BGR分离后顺序是[B, G, R]
    channels.push_back(rgbChannels[2]); // R通道
    channels.push_back(rgbChannels[1]); // G通道
    channels.push_back(rgbChannels[0]); // B通道

    // 添加Alpha通道（全0）
    channels.push_back(Mat::zeros(frame.size(), CV_8UC1));
    
    // 合并通道
    merge(channels, tmp);
}